#pragma once

#include "Sem.hpp"
#include "Mutex.hpp"
#include <vector>

namespace RingBufferModule
{
    using namespace LockModule;

    int gcap = 10;
    template <class T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap = gcap)
            : _cap(cap),
              _v(cap),
              _p_num(0),
              _c_num(0),
              _datasem(0),
              _spacesem(cap)
        {
        }

        void Equeue(T &in)
        {
            _spacesem.p(); // 有了信号量则无需判断循环队列为空或者满的特殊情况

            {
                LockGuard lockguard(_p_mutex);
                _v[_p_num] = in;
                _p_num++;
                _p_num %= _cap;
            }
            _datasem.v();
        }

        void Pop(T &out)
        {
            _datasem.p();

            {
                LockGuard lockguard(_p_mutex);
                out = _v[_c_num];
                _c_num++;
                _c_num %= _cap;
            }
            _spacesem.v();
        }

        ~RingBuffer()
        {
        }

    private:
        std::vector<T> _v;
        int _cap;
        int _p_num;
        int _c_num;

        Sem _datasem;  // 数据信号量
        Sem _spacesem; // 空间信号量

        Mutex _c_mutex; // 保证多消费者互斥访问
        Mutex _p_mutex; // 保证多生产者互斥访问
    };
}